using System;
using System.Collections.Generic;
using System.Text;

namespace EuropeEngulfed.NET
{
    class GameTurn
    {
        public enum GameDate
        {
            SepOct39,
            NovDev39,
            JanFeb40,
            MarApr40,
            MayJun40,
            JulAug40,
            SepOct40,
            NovDec40,
            JanFeb41,
            MarApr41,
            MayJun41,
            JulAug41,
            SepOct41,
            NovDec41,
            JanFeb42,
            MarApr42,
            MayJun42,
            JulAug42,
            SepOct42,
            NovDec42,
            JanFeb43,
            MarApr43,
            MayJun43,
            JulAug43,
            SepOct43,
            NovDec43,
            JanFeb44,
            MarApr44,
            MayJun44,
            JulAug44,
            SepOct44,
            NovDec44,
            JanFeb45,
            MarApr45,
            MayJun45,
            JulAug45,
            SepOct45,
            NovDec45,
            JanFeb46, //Needed for things that go past end of game e.g. restricted builds
        }

        public enum GamePhase
        {
            WeatherDeterminationPhase,
            AxisPlayerTurn,
            AlliedPlayerTurn,
        }

        public enum GameSubPhase
        {
            None,
            InitialSupplyDetermination,
            StrategicWarfare,
            Production,
            InitialOperationalMovement,
            InitialStrategicMovement,
            InitialCombat,
            BreakThrough,
            FinalSupplyDetermination,
        }

        private GameDate gameDate;
        private GamePhase gamePhase;
        private GameSubPhase gameSubPhase;

        public GameDate CurrentGameDate
        {
            get
            {
                return gameDate;
            }
        }

        public GamePhase CurrentGamePhase
        {
            get
            {
                return gamePhase;
            }
        }

        public GameSubPhase CurrentGameSubPhase
        {
            get
            {
                return gameSubPhase;
            }

            set
            {
                gameSubPhase = value;
            }
        }

        public GameTurn()
        {
            gameDate = GameDate.SepOct39;
            gamePhase = GamePhase.WeatherDeterminationPhase;
            gameSubPhase = GameSubPhase.None;
        }

        public GameTurn(GameDate gameDate,GamePhase gamePhase,GameSubPhase gameSubPhase)
        {
            this.gameDate = gameDate;
            this.gamePhase = gamePhase;
            this.gameSubPhase = gameSubPhase;
        }

        public static GameTurn operator ++(GameTurn gameTurnToIncrement)
        {
            if (gameTurnToIncrement.gamePhase == GamePhase.WeatherDeterminationPhase)
            {
                gameTurnToIncrement.gamePhase++;
                gameTurnToIncrement.gameSubPhase = GameSubPhase.InitialSupplyDetermination;
            }
            else if (gameTurnToIncrement.gameSubPhase == GameSubPhase.FinalSupplyDetermination)
            {
                if (gameTurnToIncrement.gamePhase == GamePhase.AlliedPlayerTurn)
                {
                    gameTurnToIncrement.gamePhase = GamePhase.WeatherDeterminationPhase;
                    if (gameTurnToIncrement.gameDate == GameDate.NovDec45)
                        throw new System.InvalidOperationException();
                    else
                        gameTurnToIncrement.gameDate++;
                }
                else
                {
                    gameTurnToIncrement.gamePhase++;
                    gameTurnToIncrement.gameSubPhase = GameSubPhase.InitialSupplyDetermination;
                }
            }
            else
                gameTurnToIncrement.gameSubPhase++;
            return gameTurnToIncrement;
        }

        public System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("GameTurn");
            System.Xml.XmlNode gameDateNode = xml.CreateElement("GameDate");
            System.Xml.XmlNode gamePhaseNode = xml.CreateElement("GamePhase");
            System.Xml.XmlNode gameSubPhaseNode = xml.CreateElement("GameSubPhase");
            gameDateNode.InnerText = Enum.GetName(typeof(GameTurn.GameDate), this.CurrentGameDate);
            gamePhaseNode.InnerText = Enum.GetName(typeof(GameTurn.GamePhase), this.CurrentGamePhase);
            gameSubPhaseNode.InnerText = Enum.GetName(typeof(GameTurn.GameSubPhase), this.CurrentGameSubPhase);
            nodeToReturn.AppendChild(gameDateNode);
            nodeToReturn.AppendChild(gamePhaseNode);
            nodeToReturn.AppendChild(gameSubPhaseNode);
            return nodeToReturn;
        }

        public static GameTurn Deserialise(System.Xml.XmlNode node)
        {
            GameTurn gameTurnToReturn = new GameTurn();
            if (node.Name == "GameTurn")
            {
                foreach (System.Xml.XmlNode gameTurnNode in node)
                {
                    switch (gameTurnNode.Name)
                    {
                        case "GameDate":
                            gameTurnToReturn.gameDate = (GameDate)Enum.Parse(typeof(GameDate), gameTurnNode.InnerText);
                            break;
                        case "GamePhase":
                            gameTurnToReturn.gamePhase = (GamePhase)Enum.Parse(typeof(GamePhase), gameTurnNode.InnerText);
                            break;
                        case "GameSubPhase":
                            gameTurnToReturn.gameSubPhase = (GameSubPhase)Enum.Parse(typeof(GameSubPhase), gameTurnNode.InnerText);
                            break;
                    }
                }
            }

            return gameTurnToReturn;
        }

        public static string GameSubPhaseToString(GameSubPhase gameSubPhase)
        {
            switch(gameSubPhase)
            {
                case GameSubPhase.BreakThrough:
                    return "Break Through Phase";
                case GameSubPhase.FinalSupplyDetermination:
                    return "Final Supply Determination";
                case GameSubPhase.InitialCombat:
                    return "Initial Combat";
                case GameSubPhase.InitialOperationalMovement:
                    return "Initial Operation Movement";
                case GameSubPhase.InitialStrategicMovement:
                    return "Initial Strategic Movement";
                case GameSubPhase.InitialSupplyDetermination:
                    return "Initial Supply Determination";
                case GameSubPhase.None:
                    return "None";
                case GameSubPhase.Production:
                    return "Production";
                case GameSubPhase.StrategicWarfare:
                    return "Strategic Warfare";
            }

            return "";
        }

        public static string GamePhaseToString(GamePhase gamePhase)
        {
            switch(gamePhase)
            {
                case GamePhase.AxisPlayerTurn:
                    return "Axis Player Turn";
                case GamePhase.AlliedPlayerTurn:
                    return "Allied Player Turn";
                case GamePhase.WeatherDeterminationPhase:
                    return "Weather Determination Phase";
            }

            return "";
        }

        /// <summary>
        /// Converts a packed 8- or 10-character game date (e.g. SepOct39 or NovDec1891) to a formatted date (e.g. Sep-Oct 1939).  
        /// Adds '19' in front of a 2-digit year.
        /// </summary>
        /// <param name="gameDate">GameDate enum</param>
        /// <returns>formatted date, e.g. Sep-Oct 1939</returns>
        public static string GameDateToString(GameDate gameDate)
        {
            int length = gameDate.ToString().Length;
            if (length != 8 && length != 10)
            {
                throw new ArgumentOutOfRangeException("Invalid game date");
            }

            StringBuilder sb = new StringBuilder(gameDate.ToString());
            sb.Insert(3, "-");                                          // insert month separator

            if (length == 8)                                            // ignore if century value already present
            {
                sb.Insert(7, " 19");
            }

            return sb.ToString();
        }

        public bool Equals(GameTurn gameTurnToCompare)
        {
            if (this.gameDate != gameTurnToCompare.gameDate)
                return false;
            if (this.gamePhase != gameTurnToCompare.gamePhase)
                return false;
            if (this.gameSubPhase != gameTurnToCompare.gameSubPhase)
                return false;

            return true;
        }
    }
}
